define([ "ng", "$", "_", "bootstrap", "notify" ], function(angular, $, _) {

	_.mixin({
		sync : function() {
			var args = arguments;

			var fnn = undefined;
			_.each(arguments, function(asyncCall) {
				asyncCall.$promise["finally"](function() {
					if (fnn && _.every(args, '$resolved'))
						fnn();

				});
			});
			return {
				then : function(fn) {
					if (fn) {
						fnn = _.once(fn);
						if (_.every(args, '$resolved')) {
							fnn();
						}
					}
				}
			}
		}
	});

	app = angular.module("UtilModule", [ 'UserModule' ]);

	app.directive("epFileModel", function($parse, $window) {
		return {
			restrict : 'A',
			link : function(scope, elm, attrs) {

				var setter = $parse(attrs.epFileModel).assign;
				elm.bind('change', function() {
					scope.$apply(function() {
						setter(scope, elm[0].files[0])
					});

				});
			}
		}
	});

	app.factory("epModal", function() {
		var modals = {};

		var open = function(id) {
			function setModal() {
				console.log("pasa por aqui");
				if (!modals[id]) {
					var modal = $("[modal-id='" + id + "']");
					if (modal.prop("tagName") == "EP-MODAL-PANE") {
						setTimeout(setModal, 100);
					} else {

						modals[id] = modal;
						modals[id].modal('show');
					}
				} else {
					modals[id].modal('show');
				}
			}
			setModal();
		};
		var close = function(id) {
			if (!modals[id])
				modals[id] = $("[modal-id='" + id + "']");
			modals[id].modal('hide');
		};


		notify = function(message, level, position) {
			var timeout = 3000;
			if (!position)
				position = "bottom-center";
			if (level == "error")
				level = "danger";

			var div = $(".notifications." + position);
			if (!div.length) {
				div = document.createElement("div");
				$("body").append(div);
				div.setAttribute("class", "notifications " + position);
				div = $(".notifications." + position);
			}

			var style = "";
			if (position.indexOf("center") >= 0)
				style = "left: -50%;"
			var n = div.notify({
				message : {
					text : message
				},
				type : level,
				style : style
			});

			n.show();
			var handle = setTimeout(function() {
				n.hide()
			}, timeout);
			n.$note.hover(function() {
				clearTimeout(handle);
			}, function() {
				handle = setTimeout(function() {
					n.hide()
				}, timeout);
			});
			return n;
		};

		return {
			open : open,
			close : close,
			notify : notify
		};
	});

	app.factory("epCache", function(User, $window, $http) {
		var jornadas;
		if ($window.localStorage.jornadas)
			jornadas = $.parseJSON($window.localStorage.jornadas);

		var tiposDocumento;
		if ($window.localStorage.tiposDocumento) {
			tiposDocumento = $.parseJSON($window.localStorage.tiposDocumento);
		}

		var sexos;
		if ($window.localStorage.sexos) {
			sexos = $.parseJSON($window.localStorage.sexos);
		}

		var service = {
			getJornadas : function(fn) {
				if (!jornadas)
					jornadas = User.getJornadas({}, function(data) {
						$window.localStorage.jornadas = JSON.stringify(data);
						if (fn)
							fn(data);
					});
				else {
					if (fn)
						fn(jornadas);
				}
				return jornadas;
			},
			getTiposDocumento : function() {

				if (!tiposDocumento) {
					tiposDocumento = [];
					$http.get("/api/getTiposDocumento").success(
							function(data) {

								data.forEach(function(d) {
									tiposDocumento.push(d);
								})

								$window.localStorage.tiposDocumento = JSON
										.stringify(tiposDocumento);
							});
				}
				return tiposDocumento;
			},
			getSexos : function() {

				if (!sexos) {
					sexos = [];
					$http.get("/api/getSexos").success(function(data) {
						data.forEach(function(d) {
							sexos.push(d);
						});
						$window.localStorage.sexos = JSON.stringify(sexos);
					});
				}
				return sexos;
			},

		}
		return service;
	});

	app.directive("epPickList", function() {
		/**
		 * Every option in the list must always have an property id.
		 */
		return {
			templateUrl : "/common/templates/ep-pick-list.html",
			restrict : 'E',

			replace : true,
			scope : {
				options : '=',
				fieldToShow : '@',
				leftTitle : '@',
				rightTitle : '@',
				onChange : '&?'
			},
			link : function(scope, element, attrs, ctrl) {

				scope.setSelected = function(o, selected) {

					scope.onChange({
						item : o,
						selected : selected
					});
				};

				scope.dropToRight = function() {

					dragAndDrop(scope.leftOptions, scope.rightOptions);
				};

				scope.dropToLeft = function() {

					dragAndDrop(scope.rightOptions, scope.leftOptions);
				};
				scope.unselected = function(o) {
					return !o.$selected;
				}
				scope.selected = function(o) {
					return o.$selected;
				}

			}

		};
	});

	app.directive("epModalPane", function() {
		// FIXME arreglar que con la tecla ESC no se cierre
		return {
			templateUrl : "/common/templates/ep-modal-pane.html",
			restrict : 'E',
			transclude : true,
			replace : true,
			scope : {
				title : '@',
				aceptar : '&?',
				cancelar : '&?',
				cerrar : '&?',
			},
			link : function(scope, element, attrs, ctrl) {
				scope.aceptarIn = function() {
					if (scope.aceptar)
						scope.aceptar();
				};
				scope.cerrarIn = function() {
					if (scope.cerrar)
						scope.cerrar();
					element.modal('hide');
				};
				scope.cancelarIn = function() {
					if (scope.cancelar)
						scope.cancelar();
					element.modal('hide');
				};

			}

		};
	});

	app.directive("epOpenModal", function() {

		return {

			restrict : 'A',

			scope : {
				epOpenModal : '@'
			},
			link : function(scope, element, attrs, ctrl) {

				var modal;
				element.click(function() {
					if (!modal)
						modal = $("[modal-id='" + scope.epOpenModal + "']");
					modal.modal('show');

				})
			}

		};
	});

	app.directive("epFormularioPersona", function() {
		return {
			restrict : 'E',
			replace : true,
			templateUrl : "/common/templates/ep-formulario-persona.html",
			scope : {
				persona : '=',
				buscadorPersona : "&"
			},
			controller : function($scope, epCache, $window, epChanging) {
				$scope.tiposDocumento = epCache.getTiposDocumento();
				$scope.sexos = epCache.getSexos();

				console.log($scope.buscadorPersona);
				$scope.changeDocumento = function() {
					epChanging($scope, 1300, function() {
						$scope.buscadorPersona({
							documento : $scope.persona.documento,
							callback : function(data) {
								if (data.length == 1)
									$scope.persona = data[0];
							}
						});
					});
				}

			}
		}
	});

	app.directive("epDraggable",
			function() {
				return {
					restrict : 'A',
					scope : {
						epDraggable : '='
					},
					link : function(scope, element, attrs, ctrl) {
						element.attr("draggable", true);

						element[0].ondragstart = function(ev) {

							ev.dataTransfer.setData("ep-data", JSON
									.stringify(scope.epDraggable));
						}

					}
				};
			});

	app.directive("epDroppable", function() {
		return {
			restrict : 'A',
			scope : {
				epDroppable : '&'
			},
			link : function(scope, element, attrs, ctrl) {

				element[0].ondragover = function(e) {
					e.preventDefault();
				}

				// element[0].ondragenter = function(e) {
				//					
				// element.addClass("ep-dragover");
				// }
				// element[0].ondragleave = function(e) {
				//					
				// element.removeClass("ep-dragover");
				// }

				element[0].ondrop = function(ev) {

					// element.removeClass("ep-dragover");
					var data = ev.dataTransfer.getData("ep-data");

					scope.$apply(function() {
						scope.epDroppable({
							item : JSON.parse(data)
						})
					});

				}

			}
		};
	});
	app.directive("epStacker", function() {
		return {
			restrict : 'E',
			scope : {
				stack : "=",
				stackName : "@",
				itemAs : "@",
				add : "&",
				remove : "&",
				see : '&?'

			},
			templateUrl : "/common/templates/ep-stacker.html",
			replace : true,
			link : function(scope, element, attrs, ctrl) {
				scope.addItem = function() {
					scope.add();
				};
			}
		};
	});

	app.directive("epAutocomplete", function() {
		// FIXME tiene lios de interaccion (de todo)
		return {
			restrict : 'A',
			templateUrl : "/common/templates/ep-combobox.html",
			replace : true,
			scope : {
				epDatasource : '=',

			},
			controller : function($scope, filterFilter) {

				$scope.optionsF = $scope.epOptions;
				var x = {};

				$scope.$watch("searchText", function() {

					x[$scope.epAs] = $scope.searchText;

					$scope.optionsF = filterFilter($scope.epOptions, x);
					if ($scope.optionsF)
						if ($scope.optionsF.length)
							$scope.selectedValue = $scope.optionsF[0];

				});

			},
			link : function(scope, element, attrs, controller) {
				scope.searchText = "";
				var input = element.find("input");
				var autocomplete = element.find("select");
				$.each(element.attr('class').split(/\s+/), function(index, item) {

					element.removeClass(item);
					input.addClass(item);
					autocomplete.addClass(item);
				});

				input.focus(function() {
					autocomplete.css({
						top : ((input.height() + 12) + "px"),
						"min-width" : (input.width() + 12) + "px"
					});
				})
				var key = {
					up : 38,
					down : 40,
					esc : 27,
					enter : 13,
					tab : 9
				}
				input.keydown(function(e) {
					if (e.which == key.up || e.which == key.down) {
						e.preventDefault();
					}
					if (e.which == key.esc)
						e.preventDefault();
				});
				input.keyup(function(e) {
					if (e.which == key.down) {
						scope.sel = true;
						autocomplete.focus();
					}
					if (e.which == key.esc)
						e.preventDefault();
				});
				scope.updateModel = function() {
					scope.epModel = scope.selectedValue;
					scope.searchText = scope.selectedValue[scope.epAs];
					scope.inp = false;
					scope.sel = false;
					scope.epOnChange();

				};
				scope.updateList = function() {
					scope.inp = true;

				};
				autocomplete.keydown(function(e) {
					if (e.which != key.down && e.which != key.up && e.which != key.enter
							&& e.which != key.tab)

						input.focus();
					if (e.which != key.down && e.which != key.up)
						e.preventDefault();
				});
				element.keypress(function(e) {

					switch (e.which) {
					case key.esc:
						scope.inp = false;
						scope.sel = false;
						e.preventDefault();
						break;
					case key.enter:
						scope.updateModel();
						e.preventDefault();
						break;
					}

					scope.$apply();
				});

			}

		};
	});

	app.factory("epLoading", function(epModal) {
		return function(promise, selector) {
			var element = $(selector);
			// En caso que haya fallado antes
			element.removeClass("ep-loading-error");

			element.addClass("ep-loading");
			promise.$promise["then"](function() {
				// element.addClass("ep-loading-success");
				epModal("Guardado");
				setTimeout(function() {
					element.removeClass("ep-loading-success");
				}, 3000);
			});
			promise.$promise["catch"](function(e) {
				element.addClass("ep-loading-error");
				epModal.notify(e.data, "error");

			});
			promise.$promise["finally"](function() {
				element.removeClass("ep-loading");
			});
		};
	});

	app.factory("epChanging", function() {
		return function(scope, timeout, fun) {
			if (scope.timer != undefined) {
				clearTimeout(scope.timer);
				delete scope.timer;
			}
			scope.timer = setTimeout(function() {
				delete scope.timer;
				fun();
			}, timeout);
		};
	});
	app.directive("epTokenizer", function($parse) {
		return {
			replace : true,
			restrict : 'A',
			templateUrl : "/common/templates/ep-tokenizer.html",
			transclude : true,
			scope : {
				epTokenizer : '=',
				epTokenAs : '@',
				epRemoveToken : '&',
			},
			link : function(scope, element, attrs, ctrl) {
				scope.as = $parse(scope.epTokenAs);
				scope.removeToken = function(token) {
					scope.epRemoveToken({
						token : token
					});
				}
			}
		}
	});

	return app;
});
